/* 
 * Copyright (c) 2019, CENTRIN.CIYUN.LTD. All rights reserved.
 */
package com.cory.admin.sys.controller.portal;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSONObject;
import com.cory.admin.sys.config.AdminConfig;
import com.cory.admin.sys.config.AdminConstants;
import com.cory.admin.sys.config.DataCryptServlet.DataCrypt;
import com.cory.admin.sys.core.handle.LoginHandle;
import com.cory.admin.sys.core.handle.SystemHandle;
import com.cory.admin.sys.domain.AdminPrincipal;
import com.cory.admin.sys.domain.entity.SysLoginLog;
import com.cory.admin.sys.domain.entity.SysResource;
import com.cory.admin.sys.domain.entity.SysUser;
import com.cory.admin.sys.enums.EResourceType;
import com.cory.admin.sys.service.SysLoginLogService;
import com.cory.admin.sys.service.SysResourceService;
import com.cory.admin.sys.service.SysUserService;
import com.cory.boot.base.BaseController;
import com.cory.boot.component.cache.RedisUtils;
import com.cory.boot.domain.CustomRuntimeException;
import com.cory.boot.domain.bean.Result;
import com.cory.boot.domain.enumdef.EDataFlag;
import com.cory.boot.domain.enumdef.EState;
import com.cory.boot.utils.CommonData;
import com.cory.module.msg.admin.AdminMsgService;
import com.cory.utils.security.CoderUtils;
import com.cory.utils.web.CookieUtils;
import com.cory.utils.web.WebUtils;
import com.google.common.collect.Lists;

/**
 * 登录
 * @author xiongcong
 * @date 2019-02-23
 */
@Controller
@RequestMapping("login")
public class LoginController extends BaseController {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysResourceService sysResourceService;
    @Autowired
    private SysLoginLogService sysLoginLogService;
    @Autowired
    private AdminConfig adminConfig;
    @Autowired
    private LoginHandle loginHandle;
    @Autowired
    private SystemHandle systemHandle;
    @Autowired
    private AdminMsgService adminMsgService;
    
    @GetMapping("")
    public String login(@RequestParam Map<String, String> param, HttpSession session, Model model) {
        AdminPrincipal user = (AdminPrincipal)session.getAttribute(AdminConstants.SESSION_USER_INFO);
        
        if (user != null) {
            return "redirect:/portal/index";
        }
        session.setAttribute(AdminConstants.SESSION_SYSTEM, systemHandle.systemSession());
        
        model.addAttribute("param", param);
        if (StringUtils.isNotBlank(adminConfig.getLoginPage())) {
            return adminConfig.getLoginPage();
        }
        return String.format("portal/%s/login", AdminConstants.MODEL);
    }
    
    @ResponseBody
    @PostMapping("")
    public Result<?> login(HttpSession session, HttpServletRequest request, HttpServletResponse response,
            String loginName, String password, String imageCode) {
        super.assertNotNull(loginName, password);
        
        String environment = CommonData.getStrParam("environment");
        if (adminConfig.getLoginImgCode()) {
            super.assertNotNull(imageCode);
            Object obj = session.getAttribute(AdminConstants.SESSION_IMG_CODE);
            if (obj == null) {
                return Result.fail("此次登录已过期,请重新登录");
            }
            if (!imageCode.equalsIgnoreCase(obj.toString()) && !"dev".equalsIgnoreCase(environment)) {
                return Result.fail("您的验证码输入不正确,请重新输入");
            }
            session.removeAttribute(AdminConstants.SESSION_IMG_CODE);
        }
        
        
        SysUser user = sysUserService.getByLoginName(loginName, adminConfig.getLoginUserType());
        if (user == null) {
            return Result.fail("用户名或密码不正确");
        }
        
        password = DataCrypt.getData(session, password);
        if (!user.getPassword().equals(CoderUtils.md5(password)) && !"dev".equalsIgnoreCase(environment)) {
            return Result.fail("用户名或密码不正确");
        }
        if (user.getState() != EState.ENABLE.key) {
            return Result.fail("您的账号已被禁用");
        }
        
        loginHandle.verifyUser(user);
        
        successLoginHandle(request, response, session, user);
        return Result.success("登录成功");
    }
    
    /**
     * 登录成功后的一些处理
     * @param session
     * @param user
     * @author xiongcong 2019-02-26
     */
    protected void successLoginHandle(HttpServletRequest request, HttpServletResponse response, HttpSession session, SysUser user) {
        String token = UUID.randomUUID().toString().replaceAll("-","");
        String sessionId = session.getId();
        String requestIp = WebUtils.getRemoteAddr(request);
        
        AdminPrincipal principal = new AdminPrincipal(token, user);
        principal.setUserName(StringUtils.defaultIfBlank(user.getUserName(), user.getLoginName()));
        SysLoginLog log = sysLoginLogService.addLoginLog(user, token, sessionId, requestIp);
        principal.setLoginId(log.getId());
        principal.setRequestIp(requestIp);
        
        List<SysResource> resources = Lists.newArrayList();
        if (EDataFlag.yes(user.getSuperFlag())) {
            resources = sysResourceService.selectResourceByType(user.getUserType());
        } else {
            resources = sysResourceService.selectUserResource(user.getId(), user.getUserType());
        }
        resources.removeIf(i -> {
            return StringUtils.isNotBlank(i.getAssignTenantIds()) && !Arrays.asList(i.getAssignTenantIds().split(",")).contains(principal.getTenantId());
        });
        
        List<String> permissions = resources.stream().filter(i -> StringUtils.isNotBlank(i.getPermission())).map(i -> i.getPermission()).collect(Collectors.toList());
        resources.removeIf(i -> {
            return i.getType() == EResourceType.BUTTON.key;
        });
        if (resources.size() == 0) {
            throw new CustomRuntimeException("您未分配管理权限，请联系管理员");
        }
        
        session.setAttribute(AdminConstants.SESSION_USER_RESOURCE, resources);
        session.setAttribute(AdminConstants.SESSION_USER_PERMISSION, permissions);
        
        RedisUtils.set(AdminConstants.REDIS_PREFIX_TOKEN + token, JSONObject.toJSONString(principal));
        session.removeAttribute(AdminConstants.SESSION_LOGIN_MSG);
        
        CookieUtils.setCookie(response, AdminConstants.COOKIE_TOKEN, token, 24*60*60, CommonData.getStrParam("top_cookies_domain"), "/");
        session.setAttribute(AdminConstants.SESSION_USER_INFO, principal);
        
        // 对单点登录的处理，挤掉之前已登录的用户
        String singleFlag = CommonData.getStrParam("login_single_limit");
        if (StringUtils.isNotBlank(singleFlag) && Integer.parseInt(singleFlag) == 1) {
            List<SysLoginLog> logs = sysLoginLogService.selectOnlineLoginLog(user.getLoginName(), user.getUserType());
            logs.forEach(i -> {
                if (!i.getId().equals(log.getId())) {
                    RedisUtils.del(AdminConstants.REDIS_PREFIX_TOKEN + i.getToken());
                    sysLoginLogService.addLoginoutLog(i.getId(), "同一账号登录被退出");
                    AdminConstants.MAP_LOGIN_TIP_MSG.put(i.getSessionId(), "您的帐号已在IP为" + requestIp + "的地址登录，您已被强迫下线");
                }
            });
        }
        
        // 判断是否是初始密码，如果是，会强制修改密码
        String defaultPwd = CommonData.getStrParam("default_pwd");
        if (StringUtils.isNotBlank(defaultPwd) && user.getPassword().equals(CoderUtils.md5(defaultPwd))) {
            session.setAttribute(AdminConstants.SESSION_DEFAULT_PWD, 1);
        }
        
        // 初始化个人消息
        adminMsgService.initUserAdminMsg();
    }
    
}
